package cn.cxy.sidebar

import android.content.Context
import android.graphics.*
import android.graphics.Paint.Align
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import cn.cxy.sidebar.SideBar.STYLE

/**
 * A~Z快速索引
 */
class SideBar : View {
    /** 画笔  */
    private val paint = Paint()

    /** 选中的字母索引  */
    private var index = -1

    /** 字母默认颜色  */
    private var defaultColor = Color.BLACK

    /** 字母选中颜色  */
    private var chooseColor = Color.MAGENTA

    /** 选中背景颜色  */
    private var chooseBackgroundColor = Color.LTGRAY

    /** 是否触摸  */
    private var isTouch = false

    /** 字母字体大小  */
    private var textSize = 0
    private var padding = 0
    private var rectBound: Rect? = null

    /** 字母改变监听回调  */
    private var callBack: SideBarSelectCallBack? = null

    /**
     * 设置字母数据
     */
    /** 字母数组  */
    var letters = arrayOf(
        "A", "B", "C", "D", "E", "F", "G",
        "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
        "U", "V", "W", "X", "Y", "Z", "#"
    )
    private var chooseStyle = STYLE.DEFAULT

    /**
     * 选中时背景风格
     */
    enum class STYLE(var mValue: Int) {
        /**
         * 默认：椭圆全背景
         */
        DEFAULT(0),

        /**
         * 无
         */
        NONE(1),

        /**
         * 圆形
         */
        CIRCLE(2),

        /**
         * 拉伸
         */
        STRETCH(3);

        companion object {
            fun getFromInt(value: Int): STYLE {
                for (direction in values()) {
                    if (direction.mValue == value) {
                        return direction
                    }
                }
                return DEFAULT
            }
        }

    }

    constructor(context: Context) : super(context) {
        init(context, null)
    }

    constructor(
        context: Context,
        attrs: AttributeSet?
    ) : super(context, attrs) {
        init(context, attrs)
    }

    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr) {
        init(context, attrs)
    }

    private fun init(
        context: Context,
        attrs: AttributeSet?
    ) {
        padding = (14 * resources.displayMetrics.density).toInt()
        rectBound = Rect()
        val a = context.obtainStyledAttributes(attrs, R.styleable.SideBar)
        textSize = a.getDimensionPixelSize(
            R.styleable.SideBar_android_textSize,
            TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP,
                16f,
                resources.displayMetrics
            ).toInt()
        )
        defaultColor =
            a.getColor(R.styleable.SideBar_android_textColor, Color.BLACK)
        chooseColor =
            a.getColor(R.styleable.SideBar_sideBar_chooseTextColor, Color.MAGENTA)
        chooseBackgroundColor = a.getColor(
            R.styleable.SideBar_sideBar_chooseBackgroundColor,
            Color.LTGRAY
        )
        chooseStyle = STYLE.getFromInt(a.getInt(R.styleable.SideBar_sideBar_style, 0))
        a.recycle()
    }

    /**
     * 设置字母默认色
     * @param color
     */
    fun setDefaultColor(color: Int) {
        defaultColor = color
    }

    /**
     * 设置字母选中色
     * @param color
     */
    fun setChooseColor(color: Int) {
        chooseColor = color
    }

    /**
     * 设置选中时控件的背景色
     * @param color
     */
    fun setChooseBacegroundColor(color: Int) {
        chooseBackgroundColor = color
    }

    /**
     * 设置选中时控件的风格
     * @param style
     */
    fun setChooseStyle(style: STYLE) {
        chooseStyle = style
    }

    /**
     * 文本字体大小  单位：dp
     * @param size
     */
    fun setTextSize(size: Int) {
        textSize = size
    }


    fun setOnSelectCallBack(callBack: SideBarSelectCallBack) {
        this.callBack = callBack
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        paint.textSize = textSize.toFloat()
        paint.getTextBounds("#", 0, 1, rectBound)
        val w = rectBound!!.width() + padding
        val h = rectBound!!.height() + padding
        val defaultWidth = paddingLeft + w + paddingRight
        val defaultHeight = paddingTop + h * letters.size + paddingBottom
        val width = measureHandler(widthMeasureSpec, defaultWidth)
        val height = measureHandler(heightMeasureSpec, defaultHeight)
        setMeasuredDimension(width, height)
    }

    private fun measureHandler(measureSpec: Int, defaultSize: Int): Int {
        var result = defaultSize
        val measureMode = MeasureSpec.getMode(measureSpec)
        val measureSize = MeasureSpec.getSize(measureSpec)
        if (measureMode == MeasureSpec.EXACTLY) {
            result = measureSize
        } else if (measureMode == MeasureSpec.AT_MOST) {
            result = Math.min(defaultSize, measureSize)
        }
        return result
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val width = width
        val height = height

        //字母的个数
        val len = letters.size
        //单个字母的高度
        val singleHeight = height / len
        if (isTouch && chooseBackgroundColor != Color.TRANSPARENT && chooseStyle != STYLE.NONE) { //触摸时画出背景色
            paint.isAntiAlias = true
            paint.color = chooseBackgroundColor
            if (chooseStyle == STYLE.CIRCLE) { //选中 圆形背景效果
                val maxVaule = Math.max(width, singleHeight).toFloat()
                val minVaule = Math.min(width, singleHeight).toFloat()
                canvas.drawArc(
                    RectF(
                        (maxVaule - minVaule) / 2,
                        (singleHeight * index).toFloat(),
                        singleHeight + (maxVaule - minVaule) / 2,
                        (singleHeight * index + singleHeight).toFloat()
                    ), 0f, 360f, true, paint
                )
            } else if (chooseStyle == STYLE.STRETCH) { //选中背景拉伸效果
                canvas.drawArc(
                    RectF(0f, 0f, width.toFloat(), (singleHeight * index).toFloat()),
                    0f,
                    360f,
                    true,
                    paint
                )
            } else { //默认：全椭圆背景效果
                canvas.drawArc(
                    RectF(0f, 0f, width.toFloat(), singleHeight.toFloat()),
                    180f,
                    180f,
                    true,
                    paint
                )
                canvas.drawRect(
                    RectF(
                        0f,
                        (singleHeight / 2).toFloat(),
                        width.toFloat(),
                        (height - singleHeight / 2).toFloat()
                    ), paint
                )
                canvas.drawArc(
                    RectF(0f, (height - singleHeight).toFloat(), width.toFloat(), height.toFloat()),
                    0f,
                    180f,
                    true,
                    paint
                )
            }
        }

        //画字母
        for (i in 0 until len) {

            // 设置字体格式
            paint.typeface = Typeface.DEFAULT
            paint.textAlign = Align.CENTER
            // 抗锯齿
            paint.isAntiAlias = true
            // 设置字体大小
            paint.textSize = textSize.toFloat()
            if (i == index) { //选中时的画笔颜色
                paint.color = chooseColor
            } else { //未选中时的画笔颜色
                paint.color = defaultColor
            }
            paint.isFakeBoldText = isTouch

            //要画的字母的x,y坐标
            val x = width / 2.toFloat()
            val y = singleHeight * (i + 1) - paint.measureText(letters[i]) / 2
            //画字母
            canvas.drawText(letters[i], x, y, paint)
            //重置画笔
            paint.reset()
        }
    }

    override fun dispatchTouchEvent(event: MotionEvent): Boolean {

        //当前选中字母的索引
        val index = (event.y / height * letters.size).toInt()
        //老的索引
        val oldIndex = this.index
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                isTouch = true
                if (index != oldIndex && index >= 0 && index < letters.size) {
                    this.index = index
                    callBack?.onSelect(index, letters[index])
                    invalidate()
                }
            }
            MotionEvent.ACTION_MOVE -> {
                isTouch = true
                if (index != oldIndex && index >= 0 && index < letters.size) {
                    this.index = index
                    callBack?.onSelect(index, letters[index])
                    invalidate()
                }
            }
            MotionEvent.ACTION_UP -> {
                isTouch = false
                if (index >= 0 && index < letters.size) {
                    callBack?.onSelect(index, letters[index])
                }
                this.index = -1
                invalidate()
            }
            else -> {
            }
        }
        return true
    }
}